Merge pull request #54 from rishabhjain/master

Twilio Calls

Andrew Cantino 11 ans auparavant
Parent
Commettre
38e3dfbaa5

+ 1 - 1
app/models/agents/event_formatting_agent.rb

@@ -21,7 +21,7 @@ module Agents
21 21
                  message => "Today's conditions look like <$.conditions> and high temperaure is going to be <$.high.celsius> degree Celsius.""
22 22
                  subject => "$.data"
23 23
 
24
-            JSONPaths must be between < and > . Make sure you dont use this symbols anywhere else. You can add as many keys as you like.
24
+            JSONPaths must be between < and > . Make sure you dont use these symbols anywhere else. You can add as many keys as you like.
25 25
 
26 26
             Event generated by Event Formatting Agent will be like
27 27
 

+ 53 - 26
app/models/agents/twilio_agent.rb

@@ -1,39 +1,59 @@
1 1
 require 'twilio-ruby'
2
+require 'securerandom'
2 3
 
3 4
 module Agents
4 5
   class TwilioAgent < Agent
5
-    default_schedule "every_10m"
6
+    cannot_be_scheduled!
6 7
 
7 8
     description <<-MD
8
-      The TwilioAgent receives and collects events and sends them via text message when scheduled.
9
+      The TwilioAgent receives and collects events and sends them via text message or gives you a call when scheduled.
9 10
 
10
-      It is assumed that events have a `:message`, `:text`, or `:sms` key, the value of which is sent as the content of the text message. You can use Event Formatting Agent if your event does not provide these keys.
11
+      It is assumed that events have a `:message`, `:text`, or `:sms` key, the value of which is sent as the content of the text message/call. You can use Event Formatting Agent if your event does not provide these keys.
11 12
 
12
-      Set `receiver_cell` to the number to receive text messages and `sender_cell` to the number sending them.
13
+      Set `receiver_cell` to the number to receive text messages/call and `sender_cell` to the number sending them.
13 14
 
14 15
       `expected_receive_period_in_days` is maximum number of days that you would expect to pass between events being received by this agent.
16
+
17
+      If you would like to receive calls, then set `receive_call` to true. `server_url` needs to be 
18
+      filled only if you are making calls. Dont forget to include http/https in `server_url`.
19
+
15 20
     MD
16 21
 
17 22
     def default_options
18 23
       {
19
-          :account_sid => 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
20
-          :auth_token => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
21
-          :sender_cell => 'xxxxxxxxxx',
22
-          :receiver_cell => 'xxxxxxxxxx',
23
-          :expected_receive_period_in_days => 'x'
24
+        :account_sid => 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
25
+        :auth_token => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
26
+        :sender_cell => 'xxxxxxxxxx',
27
+        :receiver_cell => 'xxxxxxxxxx',
28
+        :server_url    => 'http://somename.com:3000',
29
+        :receive_text  => 'true',
30
+        :receive_call  => 'false',
31
+        :expected_receive_period_in_days => '1'
24 32
       }
25 33
     end
26 34
 
27 35
     def validate_options
28
-      unless options[:account_sid].present? && options[:auth_token].present? && options[:sender_cell].present? && options[:receiver_cell].present? && options[:expected_receive_period_in_days].present?
29
-        errors.add(:base, 'account_sid, auth_token, sender_cell, receiver_cell, and expected_receive_period_in_days are all required')
36
+      unless options[:account_sid].present? && options[:auth_token].present? && options[:sender_cell].present? && options[:receiver_cell].present? && options[:expected_receive_period_in_days].present? && options[:receive_call].present? && options[:receive_text].present?
37
+        errors.add(:base, 'account_sid, auth_token, sender_cell, receiver_cell, receive_text, receive_call and expected_receive_period_in_days are all required')
30 38
       end
31 39
     end
32 40
 
33 41
     def receive(incoming_events)
34
-      memory[:queue] ||= []
42
+      @client = Twilio::REST::Client.new options[:account_sid], options[:auth_token]
43
+      memory[:pending_calls] ||= {}
35 44
       incoming_events.each do |event|
36
-        memory[:queue] << event.payload
45
+        message = (event.payload[:message] || event.payload[:text] || event.payload[:sms]).to_s
46
+        if message != ""
47
+          if options[:receive_call].to_s == 'true'
48
+            secret = SecureRandom.hex 3
49
+            memory[:pending_calls][secret] = message
50
+            make_call secret
51
+          end
52
+          if options[:receive_text].to_s == 'true'
53
+            message = message.slice 0..160
54
+            send_message message
55
+          end
56
+        end
37 57
       end
38 58
     end
39 59
 
@@ -41,21 +61,28 @@ module Agents
41 61
       last_receive_at && last_receive_at > options[:expected_receive_period_in_days].to_i.days.ago
42 62
     end
43 63
 
44
-    def send_message(client, message)
45
-      client.account.sms.messages.create(:from => options[:sender_cell], :to => options[:receiver_cell], :body => message)
64
+    def send_message(message)
65
+      @client.account.sms.messages.create :from => options[:sender_cell],
66
+                                          :to => options[:receiver_cell],
67
+                                          :body => message
46 68
     end
47 69
 
48
-    def check
49
-      if memory[:queue] && memory[:queue].length > 0
50
-        @client = Twilio::REST::Client.new(options[:account_sid], options[:auth_token])
51
-        memory[:queue].each do |text|
52
-          message = text[:message] || text[:text] || text[:sms]
53
-          if message
54
-            message.slice! 160, message.length
55
-            send_message @client, message
56
-          end
57
-        end
58
-        memory[:queue] = []
70
+    def make_call(secret)
71
+      @client.account.calls.create :from => options[:sender_cell],
72
+                                   :to => options[:receiver_cell],
73
+                                   :url => post_url(options[:server_url],secret)
74
+    end
75
+
76
+    def post_url(server_url,secret)
77
+      "#{server_url}/users/#{self.user.id}/webhooks/#{self.id}/#{secret}"
78
+    end
79
+
80
+    def receive_webhook(params)
81
+      create_event :payload => params
82
+      if memory[:pending_calls].has_key? params[:secret].to_sym
83
+        response = Twilio::TwiML::Response.new {|r| r.Say memory[:pending_calls][params[:secret].to_sym], :voice => 'woman'}
84
+        memory[:pending_calls].delete params[:secret].to_sym
85
+        [response.text, 200]
59 86
       end
60 87
     end
61 88
   end

+ 48 - 14
spec/models/agents/twilio_agent_spec.rb

@@ -7,35 +7,51 @@ describe Agents::TwilioAgent do
7 7
                                                      :auth_token => 'x',
8 8
                                                      :sender_cell => 'x',
9 9
                                                      :receiver_cell => 'x',
10
+                                                     :server_url    => 'http://somename.com:3000',
11
+                                                     :receive_text  => 'true',
12
+                                                     :receive_call  => 'true',
10 13
                                                      :expected_receive_period_in_days => '1' })
11 14
     @checker.user = users(:bob)
12 15
     @checker.save!
13 16
 
14 17
     @event = Event.new
15 18
     @event.agent = agents(:bob_weather_agent)
16
-    @event.payload = { :message => 'Gonna rain..' }
19
+    @event.payload = { :message => 'Looks like its going to rain' }
17 20
     @event.save!
18 21
 
19 22
     @sent_messages = []
20
-    stub.any_instance_of(Agents::TwilioAgent).send_message { |client, message| @sent_messages << message}
23
+    stub.any_instance_of(Agents::TwilioAgent).send_message { |message| @sent_messages << message}
24
+    stub.any_instance_of(Agents::TwilioAgent).make_call {}
21 25
   end
22 26
 
23 27
   describe '#receive' do
24
-    it 'should queue any payload it receives' do
28
+    it 'should make sure multiple events are being received' do
25 29
       event1 = Event.new
26 30
       event1.agent = agents(:bob_rain_notifier_agent)
27
-      event1.payload = 'Some payload'
31
+      event1.payload = { :message => 'Some message' }
28 32
       event1.save!
29 33
 
30 34
       event2 = Event.new
31 35
       event2.agent = agents(:bob_weather_agent)
32
-      event2.payload = 'More payload'
36
+      event2.payload = { :message => 'Some other message' }
33 37
       event2.save!
34 38
 
35
-      Agents::TwilioAgent.async_receive(@checker.id, [event1.id, event2.id])
36
-      @checker.reload.memory[:queue].should == ['Some payload', 'More payload']
39
+      @checker.receive([@event,event1,event2])
40
+      @sent_messages.should == ['Looks like its going to rain','Some message','Some other message']
41
+    end
42
+
43
+    it 'should check if receive_text is working fine' do
44
+      @checker.options[:receive_text] = 'false'
45
+      @checker.receive([@event])
37 46
       @sent_messages.should be_empty
38 47
     end
48
+
49
+    it 'should check if receive_call is working fine' do
50
+      @checker.options[:receive_call] = 'true'
51
+      @checker.receive([@event])
52
+      @checker.memory[:pending_calls].should_not == {}
53
+    end
54
+
39 55
   end
40 56
 
41 57
   describe '#working?' do
@@ -49,16 +65,34 @@ describe Agents::TwilioAgent do
49 65
     end
50 66
   end
51 67
 
52
-  describe '#check' do
68
+  describe "validation" do
53 69
     before do
54
-      Agents::TwilioAgent.async_receive @checker.id, [@event.id]
70
+      @checker.should be_valid
71
+    end
72
+
73
+    it "should validate presence of of account_sid" do
74
+      @checker.options[:account_sid] = ""
75
+      @checker.should_not be_valid
76
+    end
77
+
78
+    it "should validate presence of auth_token" do
79
+      @checker.options[:auth_token] = ""
80
+      @checker.should_not be_valid
81
+    end
82
+
83
+    it "should validate presence of receiver_cell" do
84
+      @checker.options[:receiver_cell] = ""
85
+      @checker.should_not be_valid
86
+    end
87
+
88
+    it "should validate presence of sender_cell" do
89
+      @checker.options[:sender_cell] = ""
90
+      @checker.should_not be_valid
55 91
     end
56 92
 
57
-    it 'should send text message and Memory should be empty after that' do
58
-      @checker.reload.memory[:queue].should == [ { :message => 'Gonna rain..' } ]
59
-      Agents::TwilioAgent.async_check(@checker.id)
60
-      @checker.reload.memory[:queue].should == []
61
-      @sent_messages.should == ['Gonna rain..']
93
+    it "should make sure filling sure filling server_url is not necessary" do
94
+      @checker.options[:server_url] = ""
95
+      @checker.should be_valid
62 96
     end
63 97
   end
64 98
 end